import socket
import threading
import datetime

# 管理聊天室的服务器部分
class ChatRoomManager:
    def __init__(self, host, port):
        self.host = host  # 服务器 IP 地址
        self.port = port  # 服务器监听的端口号
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 创建 TCP 套接字
        self.clients = {}  # 保存客户端连接信息及其昵称
        self.lock = threading.Lock()  # 确保多个线程修改 clients 时互斥

    def start(self):
        # 监听来自客户端的连接请求
        self.server_socket.bind((self.host, self.port))
        self.server_socket.listen()
        print(f'Server is listening on {self.host}:{self.port}...')

        while True:
            client_socket, addr = self.server_socket.accept()  # 接受客户端连接
            client_thread = threading.Thread(target=self.handle_client, args=(client_socket,))
            client_thread.start()  # 启动新线程处理客户端消息

    def handle_client(self, client_socket):
        # 连接成功后发送欢迎消息并获取昵称
        client_socket.send(b'Welcome to the chat room!')
        nickname = client_socket.recv(1024).decode().strip()
        self.lock.acquire()
        self.clients[client_socket] = nickname  # 保存客户端连接信息及其昵称
        self.lock.release()
        self.broadcast(f'{nickname} has joined the chat room!')  # 广播该用户的加入信息

        while True:
            try:
                message = client_socket.recv(1024).decode()  # 接收客户端消息
                if not message:
                    self.remove_client(client_socket)  # 如果读到空消息，认为客户端断开连接
                    break
                elif message.startswith('@'):  # 如果消息以 @ 开头，则是私信
                    self.direct_message(message, nickname)
                else:
                    self.broadcast(f'{nickname}: {message}')  # 否则广播该消息
            except Exception as e:
                print(e)
                self.remove_client(client_socket)  # 出现异常时关闭客户端连接
                break

    def broadcast(self, message):
        self.lock.acquire()
        for client in self.clients:
            client.send(f'{message}\n'.encode())  # 向所有客户端广播消息
        self.lock.release()

    def direct_message(self, message, sender):
        recipient, content = message[1:].split(' ', 1)  # 解析出私信对象和消息内容
        for client, nickname in self.clients.items():
            if nickname == recipient:
                client.send(f'(DM from {sender}): {content}\n'.encode())  # 向指定客户端发送私信

    def remove_client(self, client_socket):
        nickname = self.clients[client_socket]
        self.lock.acquire()
        del self.clients[client_socket]  # 删除保存的连接信息
        self.lock.release()
        self.broadcast(f'{nickname} has left the chat room.')  # 广播该用户的退出信息
        client_socket.close()



if __name__ == '__main__':
    # 启动服务器
    server = ChatRoomManager('localhost', 8888)
    server_thread = threading.Thread(target=server.start)
    server_thread.start()
